﻿using System;
using System.Net;
using System.Collections;
using Czf_Serialize;
using System.IO;
using System.Net.Sockets;
using System.Reflection;

namespace CzfSDK
{
	public delegate void UdpCallback(byte[] bytes, EndPoint endpoint);

	public class CzfProto
	{
		[ThreadStatic]
		public static CzfNetClient client;
		[ThreadStatic]
		public static Hashtable source;

        public bool debug = false;
		public bool debugProtoException = false;

		public byte parameters = 0;
		public byte method = 1;
		public byte callback = 2;
		public byte error = 3;
		public byte timestamp = 4;

		public int zipLv;

		public string defaultMethod = "";


		public CzfProto (int zipLv)
		{
			this.zipLv = zipLv;
		}

		/// <summary>
		/// 打包数据
		/// </summary>
		/// <param name="method">Method.</param>
		/// <param name="callback">Callback.</param>
		/// <param name="error">Error.</param>
		/// <param name="parameters">Parameters.</param>
		public virtual byte[] Pack(string method, string callback, int error, params object[] parameters)
		{
			var retHt = new Hashtable ();
			if(method != null)
				retHt [this.method] = method;
			retHt [this.timestamp] = DateTime.Now.Ticks;
			retHt [this.error] = error;
			retHt [this.callback] = callback;
			retHt [this.parameters] = parameters;

			if (debug) {
				CzfLog.Info ("res:"+retHt.ToJson());
			}

			byte[] bts;
			using (var writer = new CzfStreamWriter (zipLv)) {
				writer.OnError += (e) => {
					CzfLog.Error("CzfProto.Pack", e);
				};
				bts = writer.ObjectToBytes (retHt);
			}

			if (debug) {
				CzfLog.Info ("res:"+bts.Length);
			}
			return bts;
		}

		/// <summary>
		/// 解包数据并分发协议
		/// </summary>
		/// <param name="bytes">Bytes.</param>
		public virtual byte[] Unpack(byte[] bytes)
		{
			Hashtable ht;

			try{
				using (var reader = new CzfStreamReader (bytes, zipLv)) {
					ht = (Hashtable)reader.ReadObject ();
				} 
			}catch (Exception e) {
				CzfLog.Error ("OnUnpack", e);
				return null;
			}


			if (debug) {
				CzfLog.Info ("req:"+ht.ToJson());
			}

			CzfProto.source = ht;

			var method = ht.GetVal<string> (this.method, defaultMethod);
			var parameters = ht.GetVal<object[]> (this.parameters);
			var callback = ht.GetVal<string> (this.callback);

			var methodInfo = this.GetType().GetMethod(method);

			if (methodInfo == null) {
				var e = new Exception ("未定义的协议({0})".CzfFormat (method));
				CzfLog.Error ("OnReceive", e);
				return null;
			}

			if (methodInfo.ReturnType != typeof(void) && callback != null) {
				// 有返回值
				object ret = null;
				var error = 0;
				try {
					try{
						ret = methodInfo.Invoke (this, parameters);
					}catch(TargetInvocationException te){
						if(!(te.InnerException is CzfProtoException)){
							CzfLog.Error("CzfProto.Unpack", te);
						}
						if (debugProtoException) {
							CzfLog.Error("CzfProto.Unpack" + ((CzfProtoException)te.InnerException).msg + ht.ToJson(), te.InnerException);
						}
						throw te.InnerException;
					}
				} catch (CzfProtoException pe){
					if (debugProtoException) {
						CzfLog.Error("CzfProto.Unpack" + ((CzfProtoException)pe).msg + ht.ToJson(), pe);
					}
					error = pe.err;
					ret = pe.msg;
				} catch (Exception e) {
					error = 1;
					CzfLog.Error ("OnReceive", e);
				}
				return Pack (callback, method, error, ret);
			} else {
				try {
					methodInfo.Invoke (this, parameters);
				} catch (Exception e) {
					CzfLog.Error ("OnReceive Invoke " + method, e);
				}
				return null;
			}
		}

		public virtual byte[] Unpack2(byte[] bytes, out string method)
		{
			Hashtable ht;
			method = "";
			try{
				using (var reader = new CzfStreamReader (bytes, zipLv)) {
					ht = (Hashtable)reader.ReadObject ();
				} 
			}catch (Exception e) {
				CzfLog.Error ("OnUnpack", e);
				return null;
			}


			if (debug) {
				CzfLog.Info ("req:"+ht.ToJson());
			}

			CzfProto.source = ht;

			method = ht.GetVal<string> (this.method, defaultMethod);

			var parameters = ht.GetVal<object[]> (this.parameters);
			var callback = ht.GetVal<string> (this.callback);

			var methodInfo = this.GetType().GetMethod(method);

			if (methodInfo == null) {
				var e = new Exception ("未定义的协议({0})".CzfFormat (method));
				CzfLog.Error ("OnReceive", e);
				return null;
			}

			if (methodInfo.ReturnType != typeof(void) && callback != null) {
				// 有返回值
				object ret = null;
				var error = 0;
				try {
					try{
						ret = methodInfo.Invoke (this, parameters);
					}catch(TargetInvocationException te){
						if(!(te.InnerException is CzfProtoException)){
							CzfLog.Error("CzfProto.Unpack", te);
						}
						if (debugProtoException) {
							CzfLog.Error("CzfProto.Unpack" + ((CzfProtoException)te.InnerException).msg + ht.ToJson(), te.InnerException);
						}
						throw te.InnerException;
					}
				} catch (CzfProtoException pe){
					if (debugProtoException) {
						CzfLog.Error("CzfProto.Unpack" + ((CzfProtoException)pe).msg + ht.ToJson(), pe);
					}
					error = pe.err;
					ret = pe.msg;
				} catch (Exception e) {
					error = 1;
					CzfLog.Error ("OnReceive", e);
				}               
				return Pack (callback, method, error, ret);
			} else {
				try {
					methodInfo.Invoke (this, parameters);
				} catch (Exception e) {
					CzfLog.Error ("OnReceive", e);
				}
				return null;
			}
		}
	}
}

